package apis

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-admin-team/go-admin-core/sdk/api"
	"github.com/go-pay/gopay/alipay"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"sync"
	"time"
	"tuowei.com/app/admin/models"
	admindto "tuowei.com/app/admin/service/dto"
	apimodels "tuowei.com/app/api/models"
	"tuowei.com/app/api/service"
	apiservice "tuowei.com/app/api/service"
	"tuowei.com/app/api/service/dto"
	apidto "tuowei.com/app/api/service/dto"
	"tuowei.com/pkg/xlog"
)

type AliPay struct {
	api.Api
}

var OutTradeNoAliPayMap sync.Map

func (e AliPay) Pay(c *gin.Context) {
	req := &dto.AlipayReq{}
	s := service.AliPay{}
	err := e.MakeContext(c).
		Bind(req, binding.JSON, nil).
		MakeService(&s.Service).
		Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	str, err := s.AppPay(e.Context, req)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	e.OK(gin.H{"pay_params": str}, "支付参数获取成功")
	return

}

func (e AliPay) Notify(c *gin.Context) {
	xlog.Info("AliPay Notify:", c)
	err := e.MakeContext(c).MakeOrm().Errors
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}

	// 解析异步通知的参数
	//    req：*http.Request
	notifyReq, err := alipay.ParseNotifyToBodyMap(e.Context.Request) // c.Request 是 gin 框架的写法
	if err != nil {
		xlog.Error(err)
		return
	}

	//// 支付宝异步通知验签（公钥模式）
	//ok, err := alipay.VerifySign(aliPayPublicKey, notifyReq)
	//if !ok {
	//	xlog.Error(err)
	//	return
	//}
	//
	//// 支付宝异步通知验签（公钥证书模式）
	//ok, err = alipay.VerifySignWithCert("alipayCertPublicKey_RSA2.crt content", notifyReq)
	//if !ok {
	//	xlog.Error(err)
	//	return
	//}
	ptr := &json.RawMessage{}
	// 如果需要，可将 BodyMap 内数据，Unmarshal 到指定结构体指针 ptr
	err = notifyReq.Unmarshal(ptr)

	// ====异步通知，返回支付宝平台的信息====
	//    文档：https://opendocs.alipay.com/open/203/105286
	//    程序执行完后必须打印输出“success”（不包含引号）。如果商户反馈给支付宝的字符不是success这7个字符，支付宝服务器会不断重发通知，直到超过24小时22分钟。一般情况下，25小时以内完成8次通知（通知的间隔频率一般是：4m,10m,10m,1h,2h,6h,15h）
	outTradeNo := notifyReq.Get("out_trade_no")
	trade_status := notifyReq.Get("trade_status")
	if trade_status != "TRADE_SUCCESS" && trade_status != "TRADE_FINISHED" {
		xlog.Error("aliapy notifyReq trade_status:", trade_status, ";outTradeNo:", outTradeNo)
		e.Context.String(http.StatusOK, "%s", "failure")
		return
	}
	e.Context.String(http.StatusOK, "%s", "success")
	e.OK("success", "success")
	//更新订单状态为已付款，增加用户积分

	totalAmount := notifyReq.Get("total_amount")
	passbackParams, err := url.QueryUnescape(notifyReq.Get("passback_params")) //OrderType商品类型OnlineOrder，MaterialOrder,LiveOrder
	if err != nil {
		xlog.Error(err)
		return
	}
	//规避ali多次回调 重启服务本段代码无效
	if _, ok := OutTradeNoAliPayMap.Load(outTradeNo); ok {
		xlog.Error("ali多次回调 outTradeNo:", outTradeNo)
		return
	} else {
		OutTradeNoAliPayMap.Store(outTradeNo, true)
		go func(o string) {
			time.Sleep(time.Hour * 25)
			OutTradeNoAliPayMap.Delete(outTradeNo)
		}(outTradeNo)
	}
	switch passbackParams {
	case "onlineorder":
		passbackParams = "OnlineOrder"
	case "liveorder":
		passbackParams = "LiveOrder"
	case "materialorder":
		passbackParams = "MaterialOrder"
	default:
		xlog.Errorf("aliPayReq.OrderType err,aliPayReq.OrderType:%s\n", passbackParams)
		return
	}
	//解析body数据到这个结构体
	//更新订单状态
	sysOrder := SysOrder{}
	switch passbackParams {
	case "OnlineOrder", "LiveOrder":
		//
		status := 0
		e.Orm.Table("sys_link_order").Select("status").Where("order_number=?", outTradeNo).Scan(&status)
		if status == 5 {
			xlog.Error("ali多次回调 sys_link_order outTradeNo:", outTradeNo)
			return
		}
		//
		reqo := admindto.UpdateOnlineOrderRequest{}
		reqo.OrderNumber = outTradeNo
		reqo.Status = 2 //付款就完成了
		sysOrder.UpdateOnlineOrderInternal(e.Context, reqo)
		//更新linkorder
		err := e.Orm.Table("sys_link_order").Where("order_number=?", outTradeNo).Update("status", 5).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
	case "MaterialOrder":
		//
		status := 0
		e.Orm.Table("sys_link_order").Select("status").Where("order_number=?", outTradeNo).Scan(&status)
		if status >= 3 {
			xlog.Error("ali多次回调 sys_link_order outTradeNo:", outTradeNo)
			return
		}
		//
		reqm := admindto.UpdateMaterialOrderRequest{}
		reqm.OrderNumber = outTradeNo
		reqm.Status = 3 //待发货
		//更新linkorder
		err := e.Orm.Table("sys_link_order").Where("order_number=?", outTradeNo).Update("status", 3).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
		sysOrder.UpdateMaterialOrderInternal(e.Context, reqm)
	default:
		xlog.Errorf("aliPayReq.OrderType err,aliPayReq.OrderType:%s\n", passbackParams)
		return
	}

	//根据订单id查询到买家id，
	tableName := ""
	switch passbackParams {
	case "OnlineOrder", "LiveOrder":
		tableName = "sys_online_order"
	case "MaterialOrder":
		tableName = "sys_material_order"
	default:
		xlog.Errorf("aliPayReq.OrderType err,aliPayReq.OrderType:%s\n", passbackParams)
		return

	}
	type Paydb struct {
		Id      int `json:"id"`
		BuyerId int `json:"buyer_id"`
	}
	paydb := &Paydb{}
	err = e.Orm.Table(tableName).Select("id", "buyer_id").Where("order_number=?", outTradeNo).Scan(paydb).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	if paydb.BuyerId == 0 {
		xlog.Errorf("db outTradeNo: %s;buyerId:%d", outTradeNo, paydb.BuyerId)
		return
	}
	//线上课程填充班级id
	onlineClassId := 0
	//只有在线课程才需要学习
	if passbackParams == "OnlineOrder" {
		//添加learning-list 订单付款成功之后再入库
		courseId := make([]int, 0)
		err = e.Orm.Table("online_order_course").Select("course_id").Where("order_id=?", paydb.Id).Find(&courseId).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
		if len(courseId) > 0 {
			for _, c := range courseId {
				var data models.SysCourse
				err = e.Orm.Debug().Table(data.TableName()).Where("course_id = ?", c).
					First(&data).Error
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return
				}
				onlineClassId = data.OnlineClassId
				//添加learning-list
				s1 := apiservice.ApiLearningList{}
				s1.Orm = e.Orm
				req1 := apidto.SysLearningListInsertReq{}
				req1.BuyerId = paydb.BuyerId
				req1.CourseId = c
				req1.Name = data.Name
				req1.Cover = data.Cover
				req1.Subject = data.Subject

				list := &apimodels.SysLearningList{}
				err = s1.Insert(&req1, list)
				if err != nil {
					xlog.Errorf("db error: %s", err)
					return
				}
			}
		}
	}
	// 更新学员为正式学员
	err = e.Orm.Table("sys_student").Where("id = ?", paydb.BuyerId).Update("buy_status", 2).Error
	if err != nil {
		xlog.Errorf("变更学员id = %s为正式学员失败:", paydb.BuyerId)
		return
	}
	//增加积分
	float, err := strconv.ParseFloat(totalAmount, 64)
	if err != nil {
		xlog.Errorf("TotalAmount ParseInt, err:%v\n", err)
		return
	}
	sysScore := SysScore{}
	req := dto.SysScoreInsertReq{}
	req.BuyerId = paydb.BuyerId
	req.OrderNumber = outTradeNo
	req.ScoreChange = float
	req.Change = 1
	req.OrderType = passbackParams
	sysScore.AddScoreInternal(e.Context, req)
	//更新学生消费总金额
	type TotalPayS struct {
		TotalPay float64 `json:"total_pay"`
		Name     string  `json:"name"`
		UserType string  `json:"user_type"`
	}
	totalPayS := &TotalPayS{}
	err = e.Orm.Table("sys_student").Select("total_pay", "name", "user_type").Where("id=?", paydb.BuyerId).Scan(&totalPayS).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	if tableName == "sys_online_order" {
		if totalPayS.UserType != "线下" && totalPayS.UserType != "线上" {
			err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("user_type", "线上").Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
		}
		if onlineClassId != 0 {
			err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("class_id", onlineClassId).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
		}

	} else if tableName == "sys_material_order" {
		if totalPayS.UserType == "" {
			err = e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("user_type", "-").Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
		}
	}

	totalPayS.TotalPay = totalPayS.TotalPay + float*100
	if totalPayS.TotalPay > 0.00 {
		err := e.Orm.Table("sys_student").Where("id=?", paydb.BuyerId).Update("total_pay", totalPayS.TotalPay).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
	}
	s := models.SysConfigCommission{}
	err = e.Orm.Table(s.TableName()).First(&s).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	//根据分享者id， 只有特殊返佣，只有网课才会给分享者返佣，其他的一律按照上级来
	if passbackParams == "OnlineOrder" {
		type Sharedb struct {
			ShareId       int `json:"share_id"`
			IsBindOffline int `json:"is_bind_offline"`
		}
		sharedb := &Sharedb{}
		err = e.Orm.Table("sys_online_order").Select("share_id", "is_bind_offline").Where("order_number=?", outTradeNo).Scan(sharedb).Error
		if err != nil {
			xlog.Errorf("db error: %s", err)
			return
		}
		if sharedb.ShareId != 0 && sharedb.IsBindOffline == 1 {
			userLabel := ""
			err = e.Orm.Table("sys_student").Select("user_label").Where("id=?", sharedb.ShareId).Scan(&userLabel).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
			//校验该网课id是否属于vip等级管理的特殊返佣课程集合里面，否则不返佣
			courseId := make([]int, 0)
			err = e.Orm.Table("online_order_course").Select("course_id").Where("order_id=?", paydb.Id).Find(&courseId).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
			if len(courseId) > 0 {
				xlog.Errorf("该订单关联的课程为0,order_id:%s", paydb.Id)
				return
			}
			//分享者是否具有该课程的学习权限
			idid := 0
			e.Orm.Table("sys_learning_list").Select("id").Where("course_id=? and buyer_id=?", courseId[0], sharedb.ShareId).Scan(&idid)
			if idid == 0 {
				xlog.Errorf("分享者:%d,没有课程:%d的权限", sharedb.ShareId, courseId[0])
				return
			}
			//返佣比例
			commissionPercentage := 0.00

			//分享人用户类型，普通，vip，svip
			switch userLabel {
			case "普通":
				if !strings.Contains(s.UserCommissionCourseId, strconv.Itoa(courseId[0])) {
					xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-普通,order_id:%s", paydb.Id)
					return
				}
				commissionPercentage = s.UserCommissionPerSpecial
			case "VIP":
				if !strings.Contains(s.VipCommissionCourseId, strconv.Itoa(courseId[0])) {
					xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-vip,order_id:%s", paydb.Id)
					return
				}
				commissionPercentage = s.VipCommissionPercentageSpecial
			case "SVIP":
				if !strings.Contains(s.SVipCommissionCourseId, strconv.Itoa(courseId[0])) {
					xlog.Errorf("该订单关联的课程未在特殊返佣页面配置-svip,order_id:%s", paydb.Id)
					return
				}
				commissionPercentage = s.SVipCommissionPercentageSpecial
			default:
				xlog.Errorf("db userLabel: %s;sharedb.ShareId:%d", userLabel, sharedb.ShareId)
				return
			}
			//佣金计算
			com := float * commissionPercentage
			//分佣加余额
			reqB := dto.SysPayBalanceReq{}
			reqB.Balance = float32(com)
			reqB.Change = 1
			reqB.Title = "邀请人-" + totalPayS.Name
			reqB.OrderType = passbackParams
			reqB.OrderNumber = outTradeNo
			sB := service.ApiStudent{}
			sB.Orm = e.Orm

			err = sB.UpdatePayBalance(&reqB, sharedb.ShareId, c)
			if err != nil {
				xlog.Error(err)
				e.Error(500, err, err.Error())
				return
			}
			//订单更新返佣
			err = e.Orm.Table(tableName).Where("order_number=?", outTradeNo).Updates(map[string]interface{}{"commission": com}).Error
			if err != nil {
				xlog.Errorf("db error: %s", err)
				return
			}
			return
		}
	}
	//买家id查询上级是否为学生，等级
	recommender := 0
	err = e.Orm.Table("sys_student").Select("recommender").Where("id=?", paydb.BuyerId).Scan(&recommender).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	//邀请直接购买
	if recommender == 0 {
		//xlog.Errorf("db buyerId: %s;recommender:%d", paydb.BuyerId, recommender)
		return
	}
	userLabel := ""
	err = e.Orm.Table("sys_student").Select("user_label").Where("id=?", recommender).Scan(&userLabel).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}

	//返佣比例
	commissionPercentage := 0.00

	//推荐人用户类型，普通，vip，svip
	switch userLabel {
	case "普通":
		commissionPercentage = s.UserCommissionPer
	case "VIP":
		commissionPercentage = s.VipCommissionPercentage
	case "SVIP":
		commissionPercentage = s.SVipCommissionPercentage
	default:
		xlog.Errorf("db userLabel: %s;recommender:%d", userLabel, recommender)
		return
	}
	//佣金计算
	com := float * commissionPercentage
	//分佣加余额
	reqB := dto.SysPayBalanceReq{}
	reqB.Balance = float32(com)
	reqB.Change = 1
	reqB.Title = "邀请人-" + totalPayS.Name
	reqB.OrderType = passbackParams
	reqB.OrderNumber = outTradeNo
	sB := service.ApiStudent{}
	sB.Orm = e.Orm

	err = sB.UpdatePayBalance(&reqB, recommender, c)
	if err != nil {
		xlog.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	//订单更新返佣
	err = e.Orm.Table(tableName).Where("order_number=?", outTradeNo).Updates(map[string]interface{}{"commission": com}).Error
	if err != nil {
		xlog.Errorf("db error: %s", err)
		return
	}
	return

}

type UpdateOrderStatus struct {
	OrderNumber string `json:"order_number"`
	Status      int    `json:"status"`
}

type AddScore struct {
	BuyerId     int     `json:"buyer_id"`
	OrderNumber string  `json:"order_number"`
	ScoreChange float64 `json:"score_change"`
	Change      int     `json:"change"`
	//商品类型OnlineOrder，MaterialOrder,LiveOrder
	OrderType string `json:"order_type"`
}

//func addScoreTest() {
//	//增加积分
//	sysScore := SysScore{}
//	req := dto.SysScoreInsertReq{}
//	req.BuyerId = 1
//	req.OrderNumber = "12ssbcsjshfhe787"
//	req.ScoreChange = 10.00
//	req.Change = 1
//	req.OrderType = "OnlineOrder"
//	c := &gin.Context{}
//	sysScore.AddScoreInternal(c, req)
//}
//func init() {
//	go func() {
//		time.Sleep(time.Second * 20)
//		addScoreTest()
//	}()
//
//}
